Add TAL-Reverb-II plugin to test
[juce-lv2.git] / juce / source / extras / the jucer / src / model / jucer_PaintRoutine.cpp
blob0368d74541d8ca7f7059734111f41e2096c2b389
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../jucer_Headers.h"
27 #include "jucer_PaintRoutine.h"
28 #include "jucer_JucerDocument.h"
29 #include "jucer_ObjectTypes.h"
30 #include "paintelements/jucer_PaintElementUndoableAction.h"
31 #include "paintelements/jucer_PaintElementPath.h"
32 #include "paintelements/jucer_PaintElementImage.h"
33 #include "paintelements/jucer_PaintElementGroup.h"
34 #include "../ui/jucer_JucerDocumentHolder.h"
37 //==============================================================================
38 PaintRoutine::PaintRoutine()
39 : document (0),
40 backgroundColour (Colours::white)
42 clear();
45 PaintRoutine::~PaintRoutine()
47 elements.clear(); // do this explicitly before the scalar destructor because these
48 // objects will be listeners on this object
51 //==============================================================================
52 void PaintRoutine::changed()
54 if (document != 0)
55 document->changed();
58 bool PaintRoutine::perform (UndoableAction* action, const String& actionName)
60 jassert (document != 0);
62 if (document != 0)
64 return document->getUndoManager().perform (action, actionName);
66 else
68 action->perform();
69 delete action;
70 return false;
74 void PaintRoutine::setBackgroundColour (const Colour& newColour) throw()
76 backgroundColour = newColour;
77 changed();
80 void PaintRoutine::clear()
82 if (elements.size() > 0)
84 elements.clear();
85 changed();
89 //==============================================================================
90 class AddXmlElementAction : public UndoableAction
92 public:
93 AddXmlElementAction (PaintRoutine& routine_, XmlElement* xml_)
94 : routine (routine_),
95 xml (xml_)
99 ~AddXmlElementAction()
101 delete xml;
104 bool perform()
106 showCorrectTab();
107 PaintElement* newElement = routine.addElementFromXml (*xml, -1, false);
108 jassert (newElement != 0);
110 indexAdded = routine.indexOfElement (newElement);
111 jassert (indexAdded >= 0);
112 return indexAdded >= 0;
115 bool undo()
117 showCorrectTab();
118 routine.removeElement (routine.getElement (indexAdded), false);
119 return true;
122 int getSizeInUnits() { return 10; }
124 int indexAdded;
126 private:
127 PaintRoutine& routine;
128 XmlElement* xml;
130 void showCorrectTab() const
132 JucerDocumentHolder* const docHolder = JucerDocumentHolder::getActiveDocumentHolder();
134 if (docHolder != 0)
135 docHolder->showGraphics (&routine);
138 AddXmlElementAction (const AddXmlElementAction&);
139 AddXmlElementAction& operator= (const AddXmlElementAction&);
142 PaintElement* PaintRoutine::addElementFromXml (const XmlElement& xml, const int index, const bool undoable)
144 selectedPoints.deselectAll();
146 if (undoable)
148 AddXmlElementAction* action = new AddXmlElementAction (*this, new XmlElement (xml));
149 perform (action, "Add new element");
151 return elements [action->indexAdded];
153 else
155 PaintElement* const newElement = ObjectTypes::createElementForXml (&xml, this);
157 if (newElement != 0)
159 elements.insert (index, newElement);
160 changed();
162 return newElement;
166 return 0;
169 PaintElement* PaintRoutine::addNewElement (PaintElement* e, const int index, const bool undoable)
171 if (e != 0)
173 XmlElement* const xml = e->createXml();
174 delete e;
176 e = addElementFromXml (*xml, index, undoable);
178 delete xml;
181 return e;
184 //==============================================================================
185 class DeleteElementAction : public PaintElementUndoableAction <PaintElement>
187 public:
188 DeleteElementAction (PaintElement* const element)
189 : PaintElementUndoableAction <PaintElement> (element),
190 oldIndex (-1)
192 xml = element->createXml();
193 oldIndex = routine.indexOfElement (element);
196 ~DeleteElementAction()
198 delete xml;
201 bool perform()
203 showCorrectTab();
204 routine.removeElement (getElement(), false);
205 return true;
208 bool undo()
210 PaintElement* newElement = routine.addElementFromXml (*xml, oldIndex, false);
211 showCorrectTab();
212 return newElement != 0;
215 int getSizeInUnits() { return 10; }
217 private:
218 XmlElement* xml;
219 int oldIndex;
223 void PaintRoutine::removeElement (PaintElement* element, const bool undoable)
225 if (elements.contains (element))
227 if (undoable)
229 perform (new DeleteElementAction (element),
230 "Delete " + element->getTypeName());
232 else
234 selectedElements.deselect (element);
235 selectedPoints.deselectAll();
237 selectedPoints.changed (true);
238 selectedElements.changed (true);
240 elements.removeObject (element);
241 changed();
246 //==============================================================================
247 class FrontOrBackElementAction : public PaintElementUndoableAction <PaintElement>
249 public:
250 FrontOrBackElementAction (PaintElement* const element, int newIndex_)
251 : PaintElementUndoableAction <PaintElement> (element),
252 newIndex (newIndex_)
254 oldIndex = routine.indexOfElement (element);
257 bool perform()
259 showCorrectTab();
261 PaintElement* e = routine.getElement (oldIndex);
262 routine.moveElementZOrder (oldIndex, newIndex);
263 newIndex = routine.indexOfElement (e);
264 return true;
267 bool undo()
269 showCorrectTab();
270 routine.moveElementZOrder (newIndex, oldIndex);
271 return true;
274 private:
275 int newIndex, oldIndex;
278 void PaintRoutine::moveElementZOrder (int oldIndex, int newIndex)
280 jassert (elements [oldIndex] != 0);
282 if (oldIndex != newIndex && elements [oldIndex] != 0)
284 elements.move (oldIndex, newIndex);
285 changed();
289 void PaintRoutine::elementToFront (PaintElement* element, const bool undoable)
291 if (element != 0 && elements.contains (element))
293 if (undoable)
294 perform (new FrontOrBackElementAction (element, -1), "Move elements to front");
295 else
296 moveElementZOrder (elements.indexOf (element), -1);
300 void PaintRoutine::elementToBack (PaintElement* element, const bool undoable)
302 if (element != 0 && elements.contains (element))
304 if (undoable)
305 perform (new FrontOrBackElementAction (element, 0), "Move elements to back");
306 else
307 moveElementZOrder (elements.indexOf (element), 0);
311 //==============================================================================
312 const char* const PaintRoutine::clipboardXmlTag = "PAINTELEMENTS";
314 void PaintRoutine::copySelectedToClipboard()
316 if (selectedElements.getNumSelected() == 0)
317 return;
319 XmlElement clip (clipboardXmlTag);
321 for (int i = 0; i < elements.size(); ++i)
323 PaintElement* const pe = elements.getUnchecked(i);
325 if (selectedElements.isSelected (pe))
327 XmlElement* const e = pe->createXml();
328 clip.addChildElement (e);
332 SystemClipboard::copyTextToClipboard (clip.createDocument (String::empty, false, false));
335 void PaintRoutine::paste()
337 XmlDocument clip (SystemClipboard::getTextFromClipboard());
338 XmlElement* const doc = clip.getDocumentElement();
340 if (doc != 0 && doc->hasTagName (clipboardXmlTag))
342 selectedElements.deselectAll();
343 selectedPoints.deselectAll();
345 forEachXmlChildElement (*doc, e)
347 PaintElement* newElement = addElementFromXml (*e, -1, true);
349 if (newElement != 0)
350 selectedElements.addToSelection (newElement);
354 delete doc;
357 void PaintRoutine::deleteSelected()
359 const SelectedItemSet <PaintElement*> temp1 (selectedElements);
360 const SelectedItemSet <PathPoint*> temp2 (selectedPoints);
362 if (temp2.getNumSelected() > 0)
364 selectedPoints.deselectAll();
365 selectedPoints.changed (true); // synchronous message to get rid of any property components
367 // if any points are selected, just delete them, and not the element, which may
368 // also be selected..
369 for (int i = temp2.getNumSelected(); --i >= 0;)
370 temp2.getSelectedItem (i)->deleteFromPath();
372 changed();
374 else if (temp1.getNumSelected() > 0)
376 selectedElements.deselectAll();
377 selectedElements.changed (true);
379 for (int i = temp1.getNumSelected(); --i >= 0;)
380 removeElement (temp1.getSelectedItem (i), true);
382 changed();
386 void PaintRoutine::selectAll()
388 if (selectedPoints.getNumSelected() > 0)
390 PaintElementPath* path = selectedPoints.getSelectedItem (0)->owner;
392 if (path != 0)
394 for (int i = 0; i < path->getNumPoints(); ++i)
395 selectedPoints.addToSelection (path->getPoint (i));
398 else
400 for (int i = 0; i < elements.size(); ++i)
401 selectedElements.addToSelection (elements.getUnchecked (i));
405 void PaintRoutine::selectedToFront()
407 const SelectedItemSet <PaintElement*> temp (selectedElements);
409 for (int i = temp.getNumSelected(); --i >= 0;)
410 elementToFront (temp.getSelectedItem(i), true);
413 void PaintRoutine::selectedToBack()
415 const SelectedItemSet <PaintElement*> temp (selectedElements);
417 for (int i = 0; i < temp.getNumSelected(); ++i)
418 elementToBack (temp.getSelectedItem(i), true);
421 void PaintRoutine::groupSelected()
423 PaintElementGroup::groupSelected (this);
426 void PaintRoutine::ungroupSelected()
428 const SelectedItemSet <PaintElement*> temp (selectedElements);
430 for (int i = 0; i < temp.getNumSelected(); ++i)
432 PaintElementGroup* const pg = dynamic_cast <PaintElementGroup*> (temp.getSelectedItem (i));
434 if (pg != 0)
435 pg->ungroup (true);
439 void PaintRoutine::bringLostItemsBackOnScreen (const Rectangle<int>& parentArea)
441 for (int i = 0; i < elements.size(); ++i)
443 PaintElement* const c = elements[i];
445 Rectangle<int> r (c->getCurrentBounds (parentArea));
447 if (! r.intersects (parentArea))
449 r.setPosition (parentArea.getCentreX(), parentArea.getCentreY());
450 c->setCurrentBounds (r, parentArea, true);
455 void PaintRoutine::startDragging (const Rectangle<int>& parentArea)
457 for (int i = 0; i < elements.size(); ++i)
459 PaintElement* const c = elements[i];
461 Rectangle<int> r (c->getCurrentBounds (parentArea));
463 c->getProperties().set ("xDragStart", r.getX());
464 c->getProperties().set ("yDragStart", r.getY());
467 getDocument()->getUndoManager().beginNewTransaction();
470 void PaintRoutine::dragSelectedComps (int dx, int dy, const Rectangle<int>& parentArea)
472 getDocument()->getUndoManager().undoCurrentTransactionOnly();
474 if (document != 0 && selectedElements.getNumSelected() > 1)
476 dx = document->snapPosition (dx);
477 dy = document->snapPosition (dy);
480 for (int i = 0; i < selectedElements.getNumSelected(); ++i)
482 PaintElement* const c = selectedElements.getSelectedItem (i);
484 const int startX = c->getProperties() ["xDragStart"];
485 const int startY = c->getProperties() ["yDragStart"];
487 Rectangle<int> r (c->getCurrentBounds (parentArea));
489 if (document != 0 && selectedElements.getNumSelected() == 1)
491 r.setPosition (document->snapPosition (startX + dx),
492 document->snapPosition (startY + dy));
494 else
496 r.setPosition (startX + dx,
497 startY + dy);
500 c->setCurrentBounds (r, parentArea, true);
503 changed();
506 void PaintRoutine::endDragging()
508 getDocument()->getUndoManager().beginNewTransaction();
511 //==============================================================================
512 void PaintRoutine::fillWithBackground (Graphics& g, const bool drawOpaqueBackground)
514 if ((! backgroundColour.isOpaque()) && drawOpaqueBackground)
516 g.fillCheckerBoard (Rectangle<int> (0, 0, g.getClipBounds().getRight(), g.getClipBounds().getBottom()),
517 50, 50,
518 Colour (0xffdddddd).overlaidWith (backgroundColour),
519 Colour (0xffffffff).overlaidWith (backgroundColour));
521 else
523 g.fillAll (backgroundColour);
527 void PaintRoutine::drawElements (Graphics& g, const Rectangle<int>& relativeTo)
529 Component temp;
530 temp.setBounds (relativeTo);
532 for (int i = 0; i < elements.size(); ++i)
533 elements.getUnchecked (i)->draw (g, getDocument()->getComponentLayout(), relativeTo);
536 //==============================================================================
537 void PaintRoutine::dropImageAt (const File& f, int x, int y)
539 Drawable* d = Drawable::createFromImageFile (f);
541 if (d != 0)
543 Rectangle<float> bounds (d->getDrawableBounds());
544 delete d;
546 PaintElement* newElement
547 = addNewElement (ObjectTypes::createNewImageElement (this), -1, true);
549 PaintElementImage* pei = dynamic_cast <PaintElementImage*> (newElement);
551 if (pei != 0)
553 String resourceName (getDocument()->getResources().findUniqueName (f.getFileName()));
555 const BinaryResources::BinaryResource* existingResource = getDocument()->getResources().getResourceForFile (f);
557 if (existingResource != 0)
559 resourceName = existingResource->name;
561 else
563 MemoryBlock data;
564 f.loadFileAsData (data);
566 getDocument()->getResources().add (resourceName, f.getFullPathName(), data);
569 pei->setResource (resourceName, true);
571 const int imageW = (int) (bounds.getRight() + 0.999f);
572 const int imageH = (int) (bounds.getBottom() + 0.999f);
574 RelativePositionedRectangle pr;
575 pr.rect.setX (x - imageW / 2);
576 pr.rect.setY (y - imageH / 2);
577 pr.rect.setWidth (imageW);
578 pr.rect.setHeight (imageH);
580 pei->setPosition (pr, true);
582 getSelectedElements().selectOnly (pei);
587 //==============================================================================
588 const char* PaintRoutine::xmlTagName = "BACKGROUND";
590 XmlElement* PaintRoutine::createXml() const
592 XmlElement* const xml = new XmlElement (xmlTagName);
594 xml->setAttribute ("backgroundColour", colourToHex (backgroundColour));
596 for (int i = 0; i < elements.size(); ++i)
597 xml->addChildElement (elements.getUnchecked (i)->createXml());
599 return xml;
602 bool PaintRoutine::loadFromXml (const XmlElement& xml)
604 if (xml.hasTagName (xmlTagName))
606 backgroundColour = Colour (xml.getStringAttribute ("backgroundColour", colourToHex (Colours::white)).getHexValue32());
608 clear();
610 forEachXmlChildElement (xml, e)
612 PaintElement* const newElement = ObjectTypes::createElementForXml (e, this);
614 if (newElement != 0)
615 elements.add (newElement);
618 return true;
621 return false;
624 void PaintRoutine::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const
626 if (! backgroundColour.isTransparent())
627 paintMethodCode << "g.fillAll (" << colourToCode (backgroundColour) << ");\n\n";
629 for (int i = 0; i < elements.size(); ++i)
630 elements[i]->fillInGeneratedCode (code, paintMethodCode);